55
PHP - MySQLi Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 1

PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

Embed Size (px)

Citation preview

Page 1: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 1

Page 2: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

IntroduccionPHP 5 cuenta con una extension mejorada para trabajar con MySQL: Improved MySQL Extension o MySQLi. Los requisitos para utilizar la nueva extension son los siguientes:• PHP 5.x.x• MySQL 4.1.3 o superior

Ventajas• Interfase procedural y orientada a objetos (la extension estandard es solo procedural)• Estatutos preparados (prepared statements)• Parametros asociados (bound parameters)• Conexiones seguras a traves de SSL

Puede aprovechar las caracteristicas de MySQL 4.1.3 y superior como:• Subselects• Transacciones• Busquedas fulltext• Soporte a Unicodigo• Soporte Geoespacial (GIS)

Desventajas• No funciona con versiones anteriores a MySQL 4.1.3• No es compatible con las funciones de la interfase estandar de PHP para MySQL, esto es, la nueva extension

no soporta las funciones de la extension estandar.• No todas la funciones de la interfase estandar tienen un equivalente en la nueva extension

RecomendacionesAntes de utilizar la nueva extension asegurese de lo siguiente:• Que el servidor Web tiene instalado PHP 5• Que el servidor de MySQL sea version 4.1.3 o superior• Que no necesita implementar o darle mantenimiento a aplicaciones que utilicen la extension estandar

Tome en cuenta lo siguiente:• La mayoria de los servicios de alojamiento o hosting en Internet utilizan PHP 4.x.x y MySQL 4.0.x o 3.x.x• Hay una gran cantidad de codigo disponible en Internet (aplicaciones, rutinas, clases, tutoriales, utilerias, etc.)

desarrolladas con la extension estandar.• Puede habilitar al mismo tiempo la extension estandar y la mejorada, esto permite que las aplicaciones previas

sigan funcionando y que las nuevas aplicaciones puedan ser desarrolladas con la nueva extension.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 2

Page 3: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Habilitar librerias de MySQLiPara que PHP se pueda conectar con MySQL se deben habilitar las librerias, de lo contrario obtendremos mensajes de error indicando que PHP no reconoce las funciones de MySQL.

En el caso de PHP 5 en Linux se debio compilar PHP con el parametro --with-mysql y/o --with-mysqli

En el caso de PHP en Windows la librerias no estan habilitadas por defecto, hay que editar php.ini y habilitarlas. Lo que hay que hacer es localizar la linea extension=php_mysql.dll, si queremos habilitar la extension estandar y la nueva le quitamos el punto y coma. Ahora agregamos la nueva extension: extension=php_mysqli.dll

Los dll’s en esta lista se encuentran en el subdirectorio ext donde esta instalado PHP, ejemplo C:\php\ext.

Guardamos los cambios y reinicamos el servidor Web.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 3

Page 4: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Interfase Orientada a ObjetosLa interfase cuenta con tres clases predefinidas:• mysqli

Representa la conexion entre PHP y MySQL• mysqli_result

Representa el resultado que se obtiene de la ejecucion de un estatuto sql• mysqli_stmt

Representa un estatuto sql preparado.

Estas clases cuentan con varios metodos y propiedades, a continuacion veremos algunas de las mas relevantes.

mysqliPara utilizar esta interfase obtenemos una instancia del objeto mysqli:$conexion = new mysqli(host, usuario, password, base_de_datos, puerto, socket);

Si se conecta con el servidor regresa un identificador de la conexión, de lo contrario regresa un false, ejemplo:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');

Verificar errores en la conexionLa manera correcta de verificar si se presentan errores durante la conexion es como se muestra a continuacion:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');if (mysqli_connect_errno())// Codigo para manejar el error

closeRegularmente al terminarse de ejecutar la pagina php las conexiones abiertas con MySQL se cierran automaticamente; si queremos cerrar la conexión antes podemos utilizar este metodo.

Regresa un true si la conexión se cierra, false de lo contrario. $conexion->close();

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 4

Page 5: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

select_dbMetodo para cambiar la base de datos seleccionada, regresa true si logra utilizar la base de datos, false de lo contrario.$seleccionaDB = $conexion->select_db('base_de_datos');

queryMetodo para enviar estatutos SQL al servidor de MySQL, para estatutos diferentes al SELECT regresa un true o false. Para los estatutos SELECT regresa un identificador con los resultados del estatuto. La sintaxis es:$registros = $conexion->query('estatuto sql', resultmode);

El resultmode define como se manejan los registros en caso de que el estatuto SQL haya sido un SELECT, puede ser uno de estos valores:• MYSQLI_STORE_RESULT

Al ejecutar el estatuto SQL SELECT, todos los registros son almacenados en memoria del servidor Web. Esto aplica igual en caso del que el estatuto haya regresado 0 (cero) o 100,000 registros. Por omision query toma este valor.

• MYSQLI_USE_RESULT Este valor provoca que no se almacenen todos los registros automaticamente en el servidor Web, lo que puede evitar que se consuma mucha memoria del servidor en los casos en que el resultado son muchos registros. La desventaja es que no se pueden utiliza la funciones num_rows() ni data_seek(). Tampco se puede ejecutar otro estatuto SQL hasta que no se hayan obtenido todos los registros o se libere el recurso con close().

affected_rowsPropiedad que regresa el numero de registros que fueron afectados por los estatutos INSERT, UPDATE o DELETE. La sintaxis es:$registrosAfectados = $conexion->affected_rows;

insert_idUn campo con el atributo AUTO_INSERT se incrementa automaticamente cuando se inserta un nuevo registro en la tabla, esta propiedad regresa el valor generado.$valorAutoincremento = $conexion->insert_id;

errnoSi se presenta un error en una operacion con MySQL esta propiedad regresa un numero de error.$errorNumero = $conexion->errno;

errorSi se presenta un error en una operacion con MySQL esta propiedad regresa la descripcion del error.$errorDescripcion = $conexion->error;

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 5

Page 6: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

closeMetodo que libera los recursos que utilizados por los registros obtenidos, si no se utiliza este metodo los recursos son liberados automaticamente al terminar de procesar la pagina.$registros->close();

NOTAA diferencia de la extension estandar, la documentacion oficial de PHP recomienda que siempre se utilice esta funcion para liberar los recursos y no esperar a que liberen automaticamente.

Se requiere unicamente para estatutos SELECT y no para INSERT, UPDATE ni DELETE.

num_rowsPropiedad que regresa el numero de registros que regresa el estatuto SELECT.$registrosSeleccionados = $registros->num_rows;

Esta propiedad no aplica en el caso de que se haya utilizado MYSQLI_USE_RESULT.

data_seekSi se utilizo el estatuto SELECT este metodo mueve el apuntador en los registros. Regresa true si pudo posicionar el apuntador, false de lo contrario. El primer registro inicia en 0 (cero).$posicion = 0;$moverApuntador = $registros->data_seek($posicion);

Este metodo no aplica en el caso de que se haya utilizado MYSQLI_USE_RESULT.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 6

Page 7: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Ejecucion de estatutos SELECTCuando se ejecuta un estatuto SELECT y se obtiene un conjunto de registros la clase mysqli_result ofrece varios metodos de accesar dichos registros:• fetch_assoc• fetch_row• fetch_array• fetch_object

fetch_assocCrea un arreglo donde vacia el contenido de los campos de un registro, regresa los valores de los campos en un arreglo indexado por nombre. Si no hay informacion regresa null.

Ejemplo:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';$registros = $conexion->query($sql);

$registro = $registros->fetch_assoc()$registros->close();$conexion->close();

Es equivalente a crear un arreglo de esta manera:$registro = array('claveCategoria' => '1', 'categoria' => 'Bebidas')

Para leer o desplegar los campos:$claveCategoria = $registro['claveCategoria']; // 1echo "$registro[categoria] <br>"; // Bebidas

Diferencias entre un juego de registros vacio y uno con datos$sql = 'SELECT claveCategoria, categoria FROM categorias

WHERE claveCategoria = 1';$registros = $conexion->query($sql);$registro = $registros->fetch_assoc();var_export($registro); // array ( 'claveCategoria' => 1, 'categoria' => 'Bebidas', )echo $registro['categoria']; //Bebidas

$sql = 'SELECT claveCategoria, categoria FROM categorias WHERE claveCategoria = 0';

$registros = $conexion->query($sql);$registro = $registros->fetch_assoc();var_export($registro); // NULLecho $registro['categoria']; //No despliega nada ni marca error

$registros->close();$conexion->close();

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 7

Page 8: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

fetch_rowCrea un arreglo donde vacia el contenido de los campos de un registro, regresa los valores de los campos en un arreglo indexado numéricamente. Si no hay informacion regresa null.

Ejemplo:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';$registros = $conexion->query($sql);

$registro = $registros->fetch_row()$registros->close();$conexion->close();

Es equivalente a crear un arreglo de esta manera:$registro = array(0 => '1', 1=> 'Bebidas');

Para leer o desplegar los campos:$claveCategoria = $registro[0]; // 1echo "$registro[1] <br>"; // Bebidas

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 8

Page 9: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

fetch_arrayCrea un arreglo donde vacia el contenido de los campos de un registro, regresa los valores de los campos en un arreglo indexado numéricamente (como fetch_row), en un arreglo asociativo (como fetch_assoc) o ambos. Si no hay informacion regresa null.

Para un arreglo numerico:$registros->fetch_array(MYSQL_NUM)

Para un arreglo asociativo:$registros->fetch_array(MYSQL_ASSOC)

Para un arreglo numerico y asociativo:$registros->fetch_array()o$registros->fetch_array(MYSQL_BOTH)

Ejemplo:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';$registros = $conexion->query($sql);

$registro = $registros->fetch_array(MYSQL_NUM);$registros->close();

Es equivalente a crear un arreglo de esta manera:$registro = array ( 0 => '1', 1 => 'Bebidas');

$registro = $registros->fetch_array(MYSQL_ASSOC);$registros->close();

Es equivalente a crear un arreglo de esta manera:$registro = array ( 'claveCategoria' => '1', 'categoria' => 'Bebidas');

$registro = $registros->fetch_array(MYSQL_BOTH);$registros->close();$conexion->close();

Es equivalente a crear un arreglo de esta manera:$registro = array(

0 => '1', 'claveCategoria' => '1', 1 => 'Bebidas', 'categoria' => 'Bebidas');

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 9

Page 10: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

mysqli_fetch_objectCrea un objeto cuyas propiedades corresponden a los campos de los registros. Si no hay informacion regresa null.

Ejemplo:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';$registros = $conexion->query($sql);

$registro = $registros->fetch_object();$registros->close();$conexion->close();

Es equivalente a crear una clase y obtener una instancia de esta manera:class stdClass

{public $claveCategoria = '1';public $categoria = 'Bebidas';

}$registro = new stdClass;

Para leer o desplegar los campos:$claveCategoria = $registro->claveCategoria;// 1echo "$registro->categoria <br>"; // Bebidas

Diferencias entre un juego de registros vacio y uno con datos$sql = 'SELECT claveCategoria, categoria FROM categorias

WHERE claveCategoria = 1';$registros = $conexion->query($sql);$registro = $registros->fetch_object();var_export($registro); // stdClass::__set_state(array( 'claveCategoria' => '1', 'categoria' => 'Bebidas', ))echo $registro->categoria; //Bebidas

$sql = 'SELECT claveCategoria, categoria FROM categorias WHERE claveCategoria = 0';

$registros = $conexion->query($sql);$registro = $registros->fetch_object();var_export($registro); // NULLecho $registro->categoria; // ERROR !!! Trying to get property of non-object

// Correctoif($registro) // NULL evalua a false

echo $registro->categoria;

$registros->close();$conexion->close();

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 10

Page 11: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Extraer registros con un cicloLas funciones anteriores obtienen un solo registro a la vez, para recorrer todo el juego de registros se utiliza un ciclo, el ciclo mas comunmente utilizado es el while.

while (expresion) // Mientras expresion sea true el ciclo sigue{

codigo...}

Mientras que expresion evalue a un true, el ciclo se ejecuta, cuando expresion evalue a false se termina el ciclo.

$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';$registros = $conexion->query($sql);

while($registro = $registros->fetch_object())echo "$registro->claveCategoria - $registro->categoria <br>";

$registros->close();$conexion->close();

En este caso lo la expresion que evalua el while es la siguiente:while($registro) // $registro evalua a true o a false ?

echo "$registro[claveCategoria] - $registro[categoria] <br>";

Mientras que fetch_assoc regrese un arreglo a $registro, el while evalua la variable como true. Cuando se terminan los registros fetch_object le regresa un null a $registro y el while da por terminado el ciclo.

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 11

Page 12: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Ejercicio - Generar una tabla HTML con los valores de una tablaEn este ejercicio se va a generar una tabla HTML a partir del siguiente estatuto:SELECT claveProducto, producto, existencia FROM productos ORDER BY claveProducto

Ejercicio - Llenar Lista, Casillas y OpcionesEn este ejercicio se va a generar una lista HTML a partir del siguiente estatuto:SELECT claveCategoria, categoria FROM categorias ORDER BY categoria

EjercicioCódigo Fuente Puerto 80 Puerto 8080 Puerto 8085 InstructorCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 Resuelto

Ubicacion de archivos:/cursos/php/ejercicios/mysqli/tabla/

EjercicioCódigo Fuente Puerto 80 Puerto 8080 Puerto 8085 InstructorCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 Resuelto

Ubicacion de archivos:/cursos/php/ejercicios/mysqli/lista/

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 12

Page 13: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

SQL InjectionEl termino SQL Injection se refiere un hoyo de seguridad que es aprovechado para manipular las aplicaciones Web. Esta vulnerabilidad afecta no solo aplicaciones PHP, tambien afecta ASP, ASP.NET, JSP, y tecnologias similares.

Un ataque del tipo SQL Injection consiste en aprovechar la falta de validaciones para alterar los estatutos SQL buscando obtener acceso privilegiado al servidor de base de datos y/o al sistema operativo.

Un ejemplo tipico es el de una pagina de entrada o Login:

El usuario y password se verifican contra una tabla de MySQL, la estructura de la tabla de usuarios podria ser como esta:+----------+-------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+----------+-------------+------+-----+---------+----------------+| clave | int(4) | | PRI | NULL | auto_increment || usuario | varchar(60) | | | | || password | varchar(41) | | | | |+----------+-------------+------+-----+---------+----------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 13

Page 14: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

La tabla podria contener registros como estos:SELECT * FROM usuarios+-------+---------+-------------------------------------------+| clave | usuario | password |+-------+---------+-------------------------------------------+| 1 | curso | digitever || 2 | curso2 | *334A07B41E482D88A347C5D42DBB18E39F252F41 || 3 | curso3 | 00aa983d4d965235 |+-------+---------+-------------------------------------------+

Un estatuto SQL tipico para determinar si un usuario y password es valido o no es el siguiente:SELECT count(*) AS cuantos FROM usuariosWHERE usuario='curso' AND password='digitever';+---------+| cuantos |+---------+| 1 |+---------+

Un usuario/password no valido daria este resultado:SELECT count(*) AS cuantosFROM usuarios WHERE usuario='novalido' AND password='novalido';+---------+| cuantos |+---------+| 0 |+---------+

Un ataque de SQL Injection para tratar de obtener acceso consistiria en modificar el estatuto SQL de esta manera:SELECT count(*) AS cuantos FROM usuarios WHERE usuario='loquesea' AND password='' OR ''='';+---------+| cuantos |+---------+| 3 |+---------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 14

Page 15: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Regresando a la pagina de login:

La pagina se verifica si los datos del usuario y password son validos comparandolos con los campos de una base de datos.

El codigo de PHP para capturar y validar la informacion podria ser como el siguiente:$usuario = $_POST['usuario'];$password = $_POST['password']$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='$usuario' AND password='$password'";

/* El estatuto SQL enviado a MySQL quedaria asi:$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='curso' AND password='digitever'";*/$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');

$registros = $conexion->query($sql);

$registro = $registros->fetch_object();

$cuantos = $registro->cuantos;

if($cuantos > 0)codigo... // Usuario/password SI es valido

else codigo... // Usuario/password NO es valido

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 15

Page 16: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Si un usuario mailicioso no cuenta con un usuario y password validos puede utilizar un ataque SQL Injection para tratar de obtener acceso. Para hacer esto inserta estatutos SQL en los campos de captura:

El codigo PHP que no valida este tipo de ataque$usuario = $_POST['usuario'];$password = $_POST['password'];

$sql = "SELECT count(*) AS cuantos FROM usuarios WHERE usuario='$usuario' AND password='$password'";

/* El estatuto SQL enviado a MySQL quedaria asi:$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='lo_que_sea' AND password='' OR ''=''";*/

$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$registros = $conexion->query($sql);/* MySQL arroja el siguiente resultado:+---------+| cuantos |+---------+| 3 |+---------+*/$registro = $registros->fetch_object();

$cuantos = $registro->cuantos;if($cuantos > 0)

codigo... // Usuario/password SI es validoelse

codigo... // Usuario/password NO es valido

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 16

Page 17: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Higienizar los datos de entradaPara proteger las aplicaciones de este tipo de ataque es necesario evitar que se puedan enviar estatutos SQL incrustados como parte de la captura de informacion. A esto se le asigna el termino de higienizar los datos de entrada.

Cada dato que pueda formar parte de un estatuto SQL se higieniza escapando ciertos caracteres para que estos no sean interpretados como estatutos SQL por el servidor de bases de datos sino como caracteres comunes y corrientes.

Los caracteres que hay que higienizar en el caso de MySQL son los siguientes:• NULL• \x00• \n• \r• \• '• "• \x1a

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 17

Page 18: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

mysqli_real_escape_stringEsta es una funcion especifica de MySQL que escapa caracteres que pueden ser utilizados en un ataque de SQL Injection. La funcion escapa los siguientes caracteres:• '• "• \• NULL• \x00• \n• \r• \x1a

A diferencia de magic_quotes_gpc estos caracteres son definidos por MySQL y no por PHP.

$usuario = $_POST['usuario']; // lo_que_sea$password = $_POST['password']; // ' OR ''='

// Sin validar SQLInjection$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='$usuario' AND password='$password'";

/* El estatuto SQL quedaria asi:$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='lo_que_sea' AND password='' OR ''=''";*/

conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');

// Validando SQLInjection interfase orientada a objetos$usuario = $conexion->real_escape_string($usuario);$usuario = $conexion->real_escape_string($password);

$sql = "SELECT count(*) AS cuantos FROM usuarios WHERE usuario='$usuario' AND password='$password'";

/* El estatuto SQL quedaria asi:$sql = "SELECT count(*) AS cuantos FROM usuarios

WHERE usuario='lo_que_sea' AND password='\' OR \'\'=\''";

Este estatuto no regresa ningun registro*/

is_numericEsta función determina si una variable es numérica (integer o float) o si un string representa un numero. Unicamente los datos tipo string se higienizan, los numericos no.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 18

Page 19: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

get_magic_quotes_gpcEn php.ini existe una opcion que define si PHP escape automaticamente los datos provenientes de POST, GET y Cookies. Off define que no escapa automaticamente y On que si..

Si esta Off y por ejemplo si un campo de una forma o cookie contiene el dato O’Hara:$usuario = $_POST['usuario']; // O'Hara

Si esta On:$usuario = $_POST['usuario']; // O\'Hara

Los caracteres que escapa magic_quotes_gpc son los siguientes:• '• "• \• NULL

Para higienizar el dato tenemos que definir si magic_quotes_gpc esta On u Off, esto lo obtenemos con get_magic_quotes_gpc. Regresa true si esta On, false de lo contrario.

stripslashesEsta funcion remueve el caracter de la diagonal en un string.$usuario = 'O\'Hara';$usuario = stripslashes($usuario); // O'Hara

Esta funcion es necesaria porque para higienizar un dato de entrada que formara parte de un estatuto SQL primero tenemos que remover los diagonales que agrega en caso que magic_quotes_gpc este habilitado.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 19

Page 20: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Lo recomendable para higienizar los datos es crear una funcion como la siguiente:function prevenirSQLInjection($valor, $conexion){

/* Si esta habilitado magic_quotes remover los diagonalesEsto evita diagonales duplicados al aplicar mysql_real_escape_string*/

if (get_magic_quotes_gpc()) $valor = stripslashes($valor);

// Si $valor no es numerico escapar caracteres especiales if (! is_numeric($valor)) $valor = $conexion->real_escape_string($valor);

return $valor;}

$usuario = $_POST['usuario'];$password = $_POST['password'];$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$usuario = prevenirSQLInjection($usuario, $conexion);$password = prevenirSQLInjection($password, $conexion);

$sql = "SELECT count(*) AS cuantos FROM usuarios WHERE usuario='$usuario' AND password='$password'";

$registros = $conexion->query($sql);$registro = $registros->fetch_object();$cuantos = $registro->cuantos;

if($cuantos > 0)codigo... // Usuario/password SI es valido

else codigo... // Usuario/password NO es valido

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 20

Page 21: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

RecomendacionesPara evitar los ataques SQL Injection los creadores de PHP hacen las siguientes recomendaciones:

• NUNCA establecer una conexion a la base de datos utilizando un usuario con altos privilegios. Utilice siempre un usuario con privilegios limitados creado especificamente para tal proposito.

• NUNCA revele informacion relacionada con la estructura de las bases de datos. Es riesgoso incluir en mensajes de error los nombres de tablas y/o campos ya que esto proporciona informacion a usuarios maliciosos.

• SIEMPRE verifique que los datos de entrada sean del tipo esperado: numerico, string, fecha, boleano, etc. Para esto se cuenta con funciones como is_numeric, is_bool, checkdate, ctype_alpha, ctype_digit, settype, type casting, expresiones regulares, etc.

• SIEMPRE higienize los valores que formaran parte de un estatuto SQL. Para esto utilice funciones como get_magic_quotes_gpc, stripslashes, y mysqli_real_escape_string.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 21

Page 22: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Ejercicio - Validar un usuarioEn este ejercicio se va a validar que exista un usuario en una tabla de MySQL con el siguiente estatuto:SELECT count(*) AS cuantos FROM usuarios WHERE usuario='el_usuario' AND password='el_password'

Ejercicio - Generar QuerystringsEn este ejercicio se va a generar un listado de clientes a partir del siguiente estatuto:SELECT claveCliente, cliente FROM clientes ORDER BYclaveCliente

El campo se convierte en una liga que nos lleva a la pagina detalleCliente.php,a esta liga se le agrega la clave del cliente en el querystring: ?claveCliente=CACTU

El estatuto para obtener el detalle del cliente es el siguiente:SELECT * FROM clientes WHERE claveCliente = 'la_clave_del_cliente'

EjercicioCódigo Fuente Puerto 80 Puerto 8080 Puerto 8085 InstructorCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 Resuelto

Ubicacion de archivos:/cursos/php/ejercicios/mysqli/login/

EjercicioCódigo Fuente Puerto 80 Puerto 8080 Puerto 8085 InstructorCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 Resuelto

Ubicacion de archivos:/cursos/php/ejercicios/mysqli/querystring/

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 22

Page 23: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Paginando registrosCuando tenemos un numero considerable de registros a mostrar en una pagina es comun mostrar un numero limitado de registros al mismo tiempo. En estos casos se le proporciona a los usuarios una interfase para saltar o moverse de un listado de registros a otro, a esto se le denomina paginar.

Aqui tenemos un ejemplo de este tipo de interfase:

Para desarrollar esta interfase se utiliza la clausula LIMIT de MySQL:SELECT * FROM tabla LIMIT posicion en los registros(offset), cuantos registros a regresar

La posicion inicial es 0, esto es, si una tabla tiene 8 registros el primer registro esta en posicion 0, el segundo esta en posicion 1 y asi sucesivamente hasta el octavo que estaria en posicion 7. A la posision se le denomina el offset.

Ejemplo:select claveCategoria, categoria from categorias +----------------+-----------------+Offset | claveCategoria | categoria | +----------------+-----------------+ 0 | 1 | Bebidas | 1 | 2 | Condimentos | 2 | 3 | Postres | 3 | 4 | Lacteos | 4 | 5 | Granos/Cereales | 5 | 6 | Carnes | 6 | 7 | Vegetales | 7 | 8 | Mariscos | +----------------+-----------------+

Extraemos los primeros dos registros de esta manera:select claveCategoria, categoria from categorias LIMIT 0,2;+----------------+-------------+| claveCategoria | categoria |+----------------+-------------+| 1 | Bebidas || 2 | Condimentos |+----------------+-------------+

Los ultimos 2 registros (7 y 8):select claveCategoria, categoria from categorias LIMIT 6,2+----------------+-----------+| claveCategoria | categoria |+----------------+-----------+| 7 | Vegetales || 8 | Mariscos |+----------------+-----------+

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 23

Page 24: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Para crear la interfase de paginacion necesitamos definir los siguientes datos:• El total de registros que queremos paginar• Cuantos registros por pagina queremos mostrar• El total de paginas (Total de registros / Registros por pagina)• La pagina que queremos desplegar• La posicion u offset de los registros

Por ejemplo supongamos que la tabla clientes tiene 91 registros, el offset va de 0 a 90:SELECT claveCliente, cliente FROM clientes ORDER BY claveCliente +--------------+--------------------------------------+offset | claveCliente | cliente | +--------------+--------------------------------------+ 0 | ALFKI | Alfreds Futterkiste | 1 | ANATR | Ana Trujillo Emparedados y helados | 2 | ANTON | Antonio Moreno Taquería | 3 | AROUT | Around the Horn | 4 | BERGS | Berglunds snabbköp | 5 | BLAUS | Blauer See Delikatessen |

. . . .

. . . .

. . . .

. . . .85 | WANDK | Die Wandernde Kuh |

86 | WARTH | Wartian Herkku | 87 | WELLI | Wellington Importadora | 88 | WHITC | White Clover Markets | 89 | WILMK | Wilman Kala | 90 | WOLZA | Wolski Zajazd | +--------------+--------------------------------------+

Si queremos desplegar 5 registros por pagina tendriamos un total redondeado de 19 paginas:91 registros / 5 registros por pagina = 18.2 paginas

Si la division arroja decimales significa que en la ultima pagina hay entre 1 y 4 registros, no se completan los 5. Si redondeamos a 18 perderiamos los ultimos registros.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 24

Page 25: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Si se va a desplagar la pagina 3 el offset o posicion del primer registro a desplegar es el 10, el calculo es de esta manera:(Numero de pagina a desplegar - 1 pagina) * Numero de registros por pagina(3 - 1) = 22 * 5 = 10

Offset = 10

SELECT claveCliente, cliente FROM clientes ORDER BY claveCliente +--------------+--------------------------------------+Pagina offset | claveCliente | cliente | +--------------+--------------------------------------+ 1 0 | ALFKI | Alfreds Futterkiste | 1 | ANATR | Ana Trujillo Emparedados y helados | 2 | ANTON | Antonio Moreno Taquería | 3 | AROUT | Around the Horn | 4 | BERGS | Berglunds snabbköp |

2 5 | BLAUS | Blauer See Delikatessen | 6 | BLONP | Blondel père et fils | 7 | BOLID | Bólido Comidas preparadas | 8 | BONAP | Bon app' | 9 | BOTTM | Bottom-Dollar Markets |

3 10 | BSBEV | B's Beverages | 11 | CACTU | Cactus Comidas para llevar | 12 | CENTC | Centro comercial Moctezuma | 13 | CHOPS | Chop-suey Chinese | 14 | COMMI | Comércio Mineiro |

. . . . . . . . . . . . . . . . . . . . 18 85 | WANDK | Die Wandernde Kuh |

86 | WARTH | Wartian Herkku | 87 | WELLI | Wellington Importadora | 88 | WHITC | White Clover Markets | 89 | WILMK | Wilman Kala |

19 90 | WOLZA | Wolski Zajazd | +--------------+--------------------------------------+

El estatuto SQL para desplegar los registros de la pagina 3 seria este:SELECT claveCliente, cliente FROM clientes ORDER BY claveCliente LIMIT 10,5

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 25

Page 26: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Manejo de fechasMySQL almacena los campos datetime con formato YYYY-MM-DD HH:MM:SS, y los campos date como YYYY-MM-DD.

Ejemplo:describe empleados+-------------------+------------------+------+-----+---------+| Field | Type | Null | Key | Default |+-------------------+------------------+------+-----+---------+| claveEmpleado | int(10) unsigned | NO | PRI | NULL || nombre | varchar(60) | NO | | || puesto | varchar(30) | YES | | NULL || fechaNacimiento | datetime | YES | | NULL || fechaContratacion | datetime | YES | | NULL || direccion | varchar(60) | YES | | NULL || ciudad | varchar(15) | YES | | NULL || region | varchar(15) | YES | | NULL || codigoPostal | varchar(10) | YES | | NULL || pais | varchar(15) | YES | MUL | NULL || telefono | varchar(24) | YES | | NULL || extension | varchar(4) | YES | | NULL || urlFoto | varchar(255) | YES | | NULL |+-------------------+------------------+------+-----+---------+

SELECT nombre, fechanacimiento,fechacontratacion FROM empleados

ORDER BY nombre+----------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+----------+---------------------+---------------------+| Andrew | 1952-02-19 00:00:00 | 1992-08-14 00:00:00 || Anne | 1969-07-02 10:45:30 | 1994-11-15 00:00:00 || Janet | 1963-08-30 00:00:00 | 1992-04-01 00:00:00 || Laura | 1958-01-09 00:00:00 | 1994-03-05 00:00:00 || Margaret | 1958-09-19 00:00:00 | 1993-05-03 00:00:00 || Michael | 1963-07-02 00:00:00 | 1993-10-17 00:00:00 || Nancy | 1968-12-08 00:00:00 | 1992-05-01 00:00:00 || Robert | 1960-05-29 00:00:00 | 1994-01-02 00:00:00 || Steven | 1955-03-04 00:00:00 | 1993-10-17 00:00:00 |+----------+---------------------+---------------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 26

Page 27: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Seleccionar registros en base a una fechaEn un estatuto se puede especificar un campo fecha de esta manera:SELECT nombre, fechanacimiento,fechacontratacion FROM empleados WHERE fechanacimiento='1968-12-08 00:00:00'+--------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+--------+---------------------+---------------------+| Nancy | 1968-12-08 00:00:00 | 1992-05-01 00:00:00 |+--------+---------------------+---------------------+

Se pueden omitir los campos de la hora:SELECT nombre, fechanacimiento,fechacontratacion FROM empleados WHERE fechanacimiento='1968-12-08'+--------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+--------+---------------------+---------------------+| Nancy | 1968-12-08 00:00:00 | 1992-05-01 00:00:00 |+--------+---------------------+---------------------+

En caso de que esten definidos los valores HH:MM:SS estos se tienen que inlcuir en el estatuto:SELECT nombre, fechanacimiento,fechacontratacion FROM empleados WHERE fechanacimiento='1969-07-02 10:45:30'+--------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+--------+---------------------+---------------------+| Anne | 1969-07-02 10:45:30 | 1994-11-15 00:00:00 |+--------+---------------------+---------------------+

SELECT nombre, fechanacimiento,fechacontratacion FROM empleados WHERE fechanacimiento='1969-07-02'

!No regresa ningun registro¡

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 27

Page 28: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Seleccionar registros en base a un rango de fechasSupongamos una tabla como la siguiente:describe fechas+-----------+------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-----------+------------------+------+-----+---------+----------------+| clave | int(10) unsigned | NO | PRI | NULL | auto_increment || fecha | date | NO | | | || fechahora | datetime | NO | | | |+-----------+------------------+------+-----+---------+----------------+

select * from fechas+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 1 | 2008-01-01 | 2008-01-01 13:25:25 || 2 | 2008-01-05 | 2008-01-05 14:10:33 || 3 | 2008-02-10 | 2008-02-10 09:00:22 || 4 | 2008-02-12 | 2008-02-12 09:15:18 || 5 | 2008-03-15 | 2008-03-15 10:00:00 || 6 | 2008-03-17 | 2008-03-17 10:03:03 || 7 | 2008-04-20 | 2008-04-20 11:11:11 || 8 | 2008-04-22 | 2008-04-22 11:33:45 || 9 | 2008-05-25 | 2008-05-25 00:15:57 || 10 | 2008-05-25 | 2008-05-25 23:59:12 |+-------+------------+---------------------+

Podemos seleccionar un rango de fecha con BETWEEN o co los operadores >= y <=:SELECT * FROM fechas WHERE fecha BETWEEN '2008-01-01' AND '2008-02-12'SELECT * FROM fechas WHERE fecha >= '2008-01-01' AND fecha <= '2008-02-12'+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 1 | 2008-01-01 | 2008-01-01 13:25:25 || 2 | 2008-01-05 | 2008-01-05 14:10:33 || 3 | 2008-02-10 | 2008-02-10 09:00:22 || 4 | 2008-02-12 | 2008-02-12 09:15:18 |+-------+------------+---------------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 28

Page 29: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

En el caso de un campo DATE TIME hay que evitar este tipo de estatuto:SELECT * FROM fechas WHERE fechahora BETWEEN '2008-01-01' AND '2008-02-12'+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 1 | 2008-01-01 | 2008-01-01 13:25:25 || 2 | 2008-01-05 | 2008-01-05 14:10:33 || 3 | 2008-02-10 | 2008-02-10 09:00:22 |+-------+------------+---------------------+

! Falta un registro ¡ (4 | 2008-02-12 | 2008-02-12 09:15:18)

Lo seguro para este tipo de campos es incluir el rango hora:minutos:segudos con el query:SELECT * FROM fechas WHERE fechahora BETWEEN '2008-01-01 00:00:00' AND '2008-02-12 23:59:59'+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 1 | 2008-01-01 | 2008-01-01 13:25:25 || 2 | 2008-01-05 | 2008-01-05 14:10:33 || 3 | 2008-02-10 | 2008-02-10 09:00:22 || 4 | 2008-02-12 | 2008-02-12 09:15:18 |+-------+------------+---------------------+

Lo mismo aplica para una fecha en particular, por ejemplo para un campo DATE esto es valido:select * from fechas where fecha = '2008-05-25'+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 9 | 2008-05-25 | 2008-05-25 00:15:57 || 10 | 2008-05-25 | 2008-05-25 23:59:12 |+-------+------------+---------------------+

Para un campo DATE TIME esto es erroneo:SELECT * FROM fechas WHERE fechahora = '2008-05-25'

¡ No regresa ningun registro !

Esto es correcto:SELECT * FROM fechas WHERE fechahora BETWEEN '2008-05-25 00:00:00' AND '2008-05-25 23:59:59'+-------+------------+---------------------+| clave | fecha | fechahora |+-------+------------+---------------------+| 9 | 2008-05-25 | 2008-05-25 00:15:57 || 10 | 2008-05-25 | 2008-05-25 23:59:12 |+-------+------------+---------------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 29

Page 30: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Agregar un nuevo registro con fechasINSERT INTO empleados

(nombre, fechanacimiento, fechacontratacion)VALUES ('Nuevo01', '1980-01-20', '2006-10-15')

SELECT nombre, fechanacimiento,fechacontratacion FROM empleados

ORDER BY nombre;+----------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+----------+---------------------+---------------------+| Andrew | 1952-02-19 00:00:00 | 1992-08-14 00:00:00 || Anne | 1969-07-02 10:45:30 | 1994-11-15 00:00:00 || Janet | 1963-08-30 00:00:00 | 1992-04-01 00:00:00 || Laura | 1958-01-09 00:00:00 | 1994-03-05 00:00:00 || Margaret | 1958-09-19 00:00:00 | 1993-05-03 00:00:00 || Michael | 1963-07-02 00:00:00 | 1993-10-17 00:00:00 || Nancy | 1968-12-08 00:00:00 | 1992-05-01 00:00:00 || Nuevo01 | 1980-01-20 00:00:00 | 2006-10-15 00:00:00 || Robert | 1960-05-29 00:00:00 | 1994-01-02 00:00:00 || Steven | 1955-03-04 00:00:00 | 1993-10-17 00:00:00 |+----------+---------------------+---------------------+

Dependiendo de la version y configuracion de MySQL puede obtener fechas erroneas si no se utiliza el formato de fechas de MySQL, pro ejemplo:INSERT INTO empleados (nombre, fechanacimiento, fechacontratacion)

VALUES ('Nuevo02', '25/11/1975', '5/11/1995');

SELECT nombre, fechanacimiento,fechacontratacion FROM empleados

ORDER BY nombre;+----------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+----------+---------------------+---------------------+| Andrew | 1952-02-19 00:00:00 | 1992-08-14 00:00:00 || Anne | 1969-07-02 10:45:30 | 1994-11-15 00:00:00 || Janet | 1963-08-30 00:00:00 | 1992-04-01 00:00:00 || Laura | 1958-01-09 00:00:00 | 1994-03-05 00:00:00 || Margaret | 1958-09-19 00:00:00 | 1993-05-03 00:00:00 || Michael | 1963-07-02 00:00:00 | 1993-10-17 00:00:00 || Nancy | 1968-12-08 00:00:00 | 1992-05-01 00:00:00 || Nuevo01 | 1980-01-20 00:00:00 | 2006-10-15 00:00:00 || Nuevo02 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 || Robert | 1960-05-29 00:00:00 | 1994-01-02 00:00:00 || Steven | 1955-03-04 00:00:00 | 1993-10-17 00:00:00 |+----------+---------------------+---------------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 30

Page 31: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Formatear una fechaPodemos formatear la fecha con DATE_FORMAT() de MySQL: DATE_FORMAT(fecha,formato).

Sin formato:SELECT nombre, fechanacimiento, fechacontratacion

FROM empleados WHERE nombre='Anne';+--------+---------------------+---------------------+| nombre | fechanacimiento | fechacontratacion |+--------+---------------------+---------------------+| Anne | 1969-07-02 10:45:30 | 1994-11-15 00:00:00 |+--------+---------------------+---------------------+

Con formato:SELECT nombre,

DATE_FORMAT(fechanacimiento,'%d/%m/%Y %T') AS fechanacimiento, DATE_FORMAT(fechacontratacion,'%d/%m/%Y') AS fechacontratacion

FROM empleados WHERE nombre='Anne';+--------+---------------------+-------------------+| nombre | fechanacimiento | fechacontratacion |+--------+---------------------+-------------------+| Anne | 02/07/1969 10:45:30 | 15/11/1994 |+--------+---------------------+-------------------+

Entre los formatos que puede aplicar MySQL tenemos los siguientes:

formato Descripcion%d Dia del mes. Con cero al inicio para los dias 1 al 9.%e Dia del mes. Sin cero al inicio.

%m Mes.Con cero al inicio para los meses 1 al 9.%c Mes. Sin cero al inicio.

%Y Año cuatro digitos.%y Año dos digitos.

%H La hora formato de 24 horas. Con cero al inicio para las horas1 a 9.%k La hora formato de 24 horas. Sin cero al inicio.%h La hora formato 12 horas. Con cero al inicio para las horas1 a 9.%l La hora formato 12 horas. Sin cero al inicio%i Minutos. Con cero al inicio para los minutos1 a 9.%s Segundos. Con cero al inicio para los segundos1 a 9.%p AM o PM

%T Tiempo en 24 horas (HH:MM:SS)%r Tiempo en 12 horas (HH:MM:SS) seguido de AM o PM

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 31

Page 32: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Convertir una fecha MySQL a un timestamp de PHPConvertir un campo date o datetime de MySQL a un timestamp se puede hacer manualmente con codigo PHP o mediante una instruccion de MySQL.

Podemos utilizar la funcion UNIX_TIMESTAMP() para que el propio MySQL genere el timestamp:SELECT nombre, fechacontratacion FROM empleados WHERE nombre='Anne';+--------+---------------------+| nombre | fechacontratacion |+--------+---------------------+| Anne | 1994-11-15 00:00:00 |+--------+---------------------+

SELECT nombre, UNIX_TIMESTAMP(fechacontratacion) AS fechacontratacion FROM empleados WHERE nombre='Anne';

+--------+-------------------+| nombre | fechacontratacion |+--------+-------------------+| Anne | 784879200 |+--------+-------------------+

El timestamp es un numero que representa el numero de segundos que han transcurrido a partir del 1 de enero de 1970. Debido a esto debemos ser cuidadosos cuando manejamos fechas anteriores a 1970, por ejemplo:SELECT nombre, fechanacimiento FROM empleados WHERE nombre='Anne';+--------+---------------------+| nombre | fechanacimiento |+--------+---------------------+| Anne | 1969-07-02 10:45:30 |+--------+---------------------+

SELECT nombre, UNIX_TIMESTAMP(fechanacimiento) AS fechanacimiento FROM empleados WHERE nombre='Anne';

+--------+-----------------+| nombre | fechanacimiento |+--------+-----------------+| Anne | 0 |+--------+-----------------+

Como la fecha es anterior a 1970, regresa un cero.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 32

Page 33: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

En este caso es mejor recibir la fecha como string y convertirla a timestamp con PHP:$conexion = @new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = "SELECT nombre,

DATE_FORMAT(fechanacimiento,'%d/%m/%Y') AS fechanacimiento FROM empleados WHERE nombre='Anne'";

$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT)$fechaMySQL = @$registros->fetch_object(); // 02/07/1969

$fechaArreglo = explode('/',$fechaMySQL);$dia = (integer) $fechaArreglo[0]; // 2$mes = (integer) $fechaArreglo[1]; // 7$anio = (integer) $fechaArreglo[2]; // 1969

$fechaTimestamp = mktime(0,0,0,$mes, $dia,$anio); // -15789600

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 33

Page 34: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Agregar, actualizar y borrar registros

Conectarse$conexion = @new mysqli('localhost', 'curso', 'digitever', 'cursophp');

Ejecutar estatuto SELECT$sql = 'SELECT claveCategoria, categoria

FROM categorias ORDER BY claveCategoria';

$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT);

$numeroRegistros = $registros->num_rows;while ($registro = $registros->fetch_object())

echo "$registro->claveCategoria : $registro->categoria <br>";

$registros->close();

Ejecutar estatuto INSERT$sql = "INSERT INTO categorias (categoria, notas, urlImagen)

VALUES ('Nueva categoria', 'Nueva descripcion', 'Nuevo URL')";

$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT);

$registrosAfectados = $conexion->affected_rows;$claveNuevaCategoria = $conexion->insert_id;

Ejecutar estatuto UPDATE$sql = "UPDATE categorias

SET categoria = 'Actualizada' WHERE claveCategoria = $claveNuevaCategoria";

$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT);

$registrosAfectados = $conexion->affected_rows;

Ejecutar estatuto DELETE$sql = "DELETE FROM categorias WHERE claveCategoria = $claveNuevaCategoria";

$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT);

$registrosAfectados = $conexion->affected_rows;

// Cerrar conexion$conexion->close();

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 34

Page 35: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Ejercicio - Altas, bajas, cambios y consultas de la tabla de categorias

EjercicioCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 InstructorCodigo Fuente Puerto 80 Puerto 8080 Puerto 8085 Resuelto

Ubicacion de archivos:/cursos/php/ejercicios/mysqli/categorias/

El orden recomendado para trabajar con las paginas PHP es este:

• lista.php• soloLectura.php• agregar.php• insert.php• editar.php• update.php• delete.php

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 35

Page 36: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Estatutos preparadosCada vez que se envia un estatuto sql el servidor MySQL lo analiza y verifica que sea valido antes de ejecutarlo, esto consume recursos del servidor. Una manera de optimizar la ejecucion es preparar los estatutos para que MySQL conosca de antemano el tipo de estatuto que va a ejecutar.

El estatuto preparado consiste en enviarle a MySQL una especie de plantilla que puede analizar y validar, cuando se le envie el estatuto completo MySQL lo ejecuta directamente sin volver a analizarlo ni validarlo.

Ventajas• Si tenemos que ejecutar el mismo estatuto varias veces en la misma pagina PHP se optimiza su ejecucion

preparandolo previamente.• Los caracteres de comillas son escapados automaticamente al preparar el estatuto.• Es posible asignar automaticamente los valores del estatuto en campos de salida sin tener que asignarlos

manualmente.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 36

Page 37: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Interfase orientada a objetosstmt_initMetodo que inicializa el objeto para los estatutos preparados, regresa un apuntador al objeto.

$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$estatuto = $conexion->stmt_init();

prepareMetodo que envia el estatuto a MySQL para que lo valide, si es valido regresa true o false de lo contrario.

$sql = 'SELECT cliente,pais FROM clientes WHERE claveCliente = ?';$validarEstatuto = $estatuto->prepare($sql)

El caracter ? define que el valor sera asociado con una variable posteriormente.

bind_paramEste metodo asocia variables como parametros de entrada del estatuto preparado. Regresa true si puede hacer la asociacion, false de lo contrario. Al asociar la variable se define el tipo de dato con uno de estos valores:• i : Integer.• d : Double• s : String• b : Blob (objeto binario)

$claveCliente = $_POST['claveCliente'];$asociarParametro = $estatuto->bind_param('i', $claveCliente);

Al utilizar estatutos preparados los datos de entrada se higienizan automaticamente.

Es posible asociar varias variables como parametros de esta manera:$asociarParametros = $estatuto->bind_param($estatuto, 'isd', $claveCliente, $descripcion, $monto);

En este ejemplo isd define que $claveCliente es de tipo integer, $descripcion de tipo string y $monto de tipo double.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 37

Page 38: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

executeMetodo que ejecuta un estatuto preparado, regresa true si puedo ejecutar el estatuto, false de lo contrario.

$ejecutar = $estatuto->execute();

affected_rowsPropiedad que determina cuantos registros se afectaron al ejecutar estatutos INSERT, UPDATE o DELETE. Si no se pudo ejecutar el estatuto regresa un -1.

$registrosAfectados = $estatuto->affected_rows;

store_resultEn caso de ejecutar un estatuto SELECT, por default el resultado es unbuffered. Esto es, no se almacenen todos los registros automaticamente en el servidor Web, lo que puede evitar que se consuma mucha memoria del servidor en los casos en que el resultado son muchos registros.

La desventaja es que no se puede utilizar la propiedad num_rows ni el metodo data_seek() cuando el resultado es unbuffered.

Si queremos que al ejecutar el estatuto SQL SELECT, todos los registros se almacenens en memoria del servidor Web utilizamos este metodo. Regresa true o false.

$almacenarRegistros = $estatuto->store_result();

num_rowsPropiedad que regresa el numero de registros que se obtienen al ejecutar un estatuto SELECT.

$numeroRegistros = $estatuto->num_rows;

NOTAPara utilizar esta funcion previamente se debe llamar el metodo store_result().

data_seekSi se utilizo el estatuto SELECT este metodo mueve el apuntador en los registros. Regresa true si pudo posicionar el apuntador, false de lo contrario. El primer registro inicia en 0 (cero).

$posicion = 0;$moverApuntador = $estatuto->data_seek($posicion);

NOTAPara utilizar esta funcion previamente se debe llamar el metodo store_result().

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 38

Page 39: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

bind_resultSi se ejecuta un estatuto SELECT, se puede asociar campos de los registros con variables como parametros de salida del estatuto preparado. Este metodo regresa true si puede hacer la asociacion, false de lo contrario.

// 'SELECT cliente,pais FROM clientes WHERE claveCliente = ?';$asociarParametro = $estatuto->bind_result($cliente, $pais);

fetchMetod que extrae la informacion de los registros que regresa un SELECT y los asigna en las variables definidas con bind_result(). Regresa true si trae informacion, false si ocurre un error y null cuando se terminaron los registros.

while ($estatuto->fetch()){

echo "Cliente: $cliente - Pais : $pais <br>";}

free_resultMetodo que libera los recursos utilizados por un estatuto perparado. Se utiliza unicamente para estatutos SELECT cuyos resultados se almacenaron con el metodo store_result(). No regresa ningun valor.

$estatuto->free_result();

errnoPropiedad que regresa el numero de error relacionado con la ultima operacion con MySQL. Si no hay errores regresa un cero.

$errorNumero = $estatuto->errno;

mysqli_stmt_errorPropiedad que regresa la descripcion del error relacionado con la ultima operacion con MySQL. Si no hay errores regresa un string vacio.

$errorDescripcion = $estatuto->error;

closeMetodo que cierra el estatuto preparado. Regresa true o false.

$cerrarEstatuto = $estatuto->close();

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 39

Page 40: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Ejemplo: Ejecutar estatuto SELECT

// Conectarse con MySQL$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');

// Incializar estatuto preparado$estatuto = $conexion->stmt_init();

// Definir estatuto SQL y validarlo$sql = 'SELECT cliente,pais FROM clientes WHERE claveCliente = ?';$validarEstatuto = $estatuto->prepare($sql)

// Asociar parametro de entrada$claveCliente = $_POST["claveCliente"];$asociarParametro = $estatuto->bind_param('i', $claveCliente);

// Ejecutar estatuto preparado$ejecutar = $estatuto->execute();

/*En caso de necesitar saber cuantos registros nos regresa un SELECT,alamacenamos todos los registros en el servidor web.

*/$almacenarRegistros = $estatuto->store_result();

// Obtener numero de registros que regresa un SELECT$numeroRegistros = $estatuto->num_rows;

// Asociar parametros de salida$asociarParametro = $estatuto->bind_result($cliente, $pais);

// Extraer informacion de registroswhile ($estatuto->fetch())

{echo "Cliente: $cliente - Pais : $pais <br>";

}

// Si alamacenamos los registros en el servidor web, liberamos recursos$estatuto->free_result();

// Cerramos el estatuto preparado$cerrarEstatuto = $estatuto->close();

// Cerramos la conexion con MySQL$conexion->close();

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 40

Page 41: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

TransaccionesUna de las mejoras de la extension mejorada el que permite la ejecucion de transacciones, ejemplo:try

{// Transaccion$claveNuevaCategoria = false;

$sql1 = 'BEGIN';$registros = @$conexion->query($sql1, MYSQLI_STORE_RESULT);if (! $registros)

throw new Exception($conexion->error, $conexion->errno);

$sql2 = "INSERT INTO categorias (categoria, notas, urlImagen) VALUES ('Nueva01', 'Notas Nueva01', 'imagenes/nuevo01.jpg')";

$registros = @$conexion->query($sql2, MYSQLI_STORE_RESULT);if (! $registros)

throw new Exception($conexion->error, $conexion->errno);

$sql3 = "DELETE FROM categorias WHERE claveCategoria = 1";$registros = @$conexion->query($sql3, MYSQLI_STORE_RESULT);if (! $registros)

throw new Exception($conexion->error, $conexion->errno);

$sql4 = 'COMMIT';$registros = @$conexion->query($sql4, MYSQLI_STORE_RESULT);if (! $registros)

throw new Exception($conexion->error, $conexion->errno);

echo '<strong>Transaccion ejecutada correctamente</strong><hr>';}

catch (Exception $e){

$sql5 = 'ROLLBACK';$registros = @$conexion->query($sql5, MYSQLI_STORE_RESULT);echo '<strong>Transaccion no se pudo llevar a cabo</strong><br>' .

'Motivo: Se detecto una excepcion<br>' .'Codigo: ' . $e->getCode() . '<br>' .'Descripcion: ' . $e->getMessage() . '<br>' .'Archivo: ' . $e->getFile() . '<br>' .'Linea: ' . $e->getLine() . '<hr>';

}

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 41

Page 42: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Procedimientos AlmacenadosUna de las novedades de MySQL 5 es el manejo de procedimientos almacenados o stored procedures. El soporte a procedimientos almacenados de MySQL es limitado (en el caso de SQL Server u Oracle es mas extenso), esto se debe a que cuando desarrollaron la extensión mejorada (mysqli) el servidor MySQL (en ese entonces versión 4.1) no los soportaba.

RespaldosLos procedimientos almacenados no se guardan con la base de datos, se guardan por separado en la base de datos "information_schema" en la tabla "routines":SELECT * FROM information_schema.routines WHERE routine_schema = 'cursophp'; // routine_schema = base de datos

Cuando se respalda una base de datos debe asegurarse de que la herramienta que utilice incluya los procedimientos almacenados. Por ejemplo la herramienta mysqldump (respaldos modo texto) por default no incluye los procedimientos almacenados, para que los incluya es necesario especificar un parametro adicional:mysqldump --user=root --password=digitever --routines cursophp > cursophp.sql

phpMyAdminLamentablemente phpMyAdmin no soporta procedimientos almacenados, no tiene opciones para crearlos ni editarlos ni borrarlos.

NOTAEsto se verifico en la version 2.9.0.2.

PrivilegiosAl usuario que se conecta con MySQL desde PHP hay que otorgarle el privilegio EXECUTE, por ejemplo:GRANT EXECUTE on cursophp.* to 'curso'@'localhost';GRANT EXECUTE on cursophp.* to 'curso';

Cliente modo textoObtener un listado de procedimientos almacenadosSELECT * FROM information_schema.routines WHERE routine_schema = 'cursophp' \G

Notas• Sin el ; al final• cursophp es el nombre de la base de datos.• \G despliega el los campos en formato vertical en lugra de horizanotal.

Obtener detalle de un procedimiento almacenadoUSE cursophp;SHOW CREATE PROCEDURE categorias_lista;

Notas• cursophp es el nombre de la base de datos.• categorias_lista es el nombre del procedimiento almacenado.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 42

Page 43: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Procedimiento almacenado sin parametrosDefinir el procedimientoObviamente es necesario crear el procedimiento almacenado en la base de datos que estemos utilizando, por ejemplo:USE cursophp;CREATE DEFINER="root"@"localhost" PROCEDURE cursophp.categorias_lista( )READS SQL DATASELECT claveCategoria, categoria, notas, urlImagen from categorias;

Este procedimiento almacenado no recibe parametros de entrada, simplemente regresa un juego de registros.

Se manda ejecutar de esta manera:call categorias_lista();+----------------+-----------------+--------------------------+--------------------------+| claveCategoria | categoria | notas | urlImagen |+----------------+-----------------+--------------------------+--------------------------+| 1 | Bebidas | Sodas, cafe, te, cerveza | imagenes/bebidas.jpg || 2 | Condimentos | Apio, perejil | imagenes/condimentos.jpg || 3 | Postres | Pasteles, dulces | imagenes/postres.jpg || 4 | Lacteos | Queso, mantequilla | imagenes/lacteos.jpg || 5 | Granos/Cereales | Pasta, pan | imagenes/granos.jpg || 6 | Carnes | Pollo, res, puerco | imagenes/carnes.jpg || 7 | Vegetales | Tomates, lechuga | imagenes/vegetales.jpg || 8 | Mariscos | Camarones, ostiones | imagenes/mariscos.jpg |+----------------+-----------------+--------------------------+--------------------------+

PHPEl codigo para ejecutar el procedimiento seria como este:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'call categorias_lista()';$registros = $conexion->query($sql, MYSQLI_STORE_RESULT);$numeroRegistros = $registros->num_rows;$conexion->close();while ($registro = $registros->fetch_object()){echo htmlspecialchars($registro->claveCategoria,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->categoria,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->notas,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->urlImagen,ENT_QUOTES,'ISO-8859-1');echo '<br>';}$registros->close();

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 43

Page 44: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Procedimiento almacenado con parametros de entradaDefinir el procedimientoUSE cursophp;CREATE DEFINER='root'@'localhost' PROCEDURE cursophp.categorias_detalle(in_claveCategoria INT)READS SQL DATASELECT claveCategoria, categoria, notas, urlImagen FROM categorias WHERE claveCategoria = in_claveCategoria;

Este procedimiento almacenado recibe parametros de entrada y regresa un juego de registros.

Se manda ejecutar de esta manera:call categorias_detalle(1);+----------------+-----------+--------------------------+----------------------+| claveCategoria | categoria | notas | urlImagen |+----------------+-----------+--------------------------+----------------------+| 1 | Bebidas | Sodas, cafe, te, cerveza | imagenes/bebidas.jpg |+----------------+-----------+--------------------------+----------------------+

PHPEl codigo para ejecutar el procedimiento seria como este:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'call categorias_detalle(1)';$registros = $conexion->query($sql, MYSQLI_STORE_RESULT);$numeroRegistros = $registros->num_rows;$conexion->close();while ($registro = $registros->fetch_object()){echo htmlspecialchars($registro->claveCategoria,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->categoria,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->notas,ENT_QUOTES,'ISO-8859-1');echo htmlspecialchars($registro->urlImagen,ENT_QUOTES,'ISO-8859-1');echo '<br>';}$registros->close();

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 44

Page 45: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Procedimiento almacenado con parametros de salidaDefinir el procedimientoUSE cursophp;CREATE DEFINER='root'@'localhost' PROCEDURE cursophp.productos_inventariobajo_cuantos(in_existencia INT, OUT out_cuantos INT)READS SQL DATASELECT count(*)INTO out_cuantosFROM productosWHERE existencia < in_existencia;

Este procedimiento almacenado recibe parametros de entrada y regresa un valor con un parametro de salida.

Este tipo de procedimiento almacenado requiere de ejecutar dos estatutos: Uno para ejecutar el procedimiento almacenado y otro para obtener el valor del parametro de salida.Se manda ejecutar de esta manera:call productos_inventariobajo_cuantos(10,@out_cuantos);Nota: no regresa nada.select @out_cuantos;+--------------+| @out_cuantos |+--------------+| 12 |+--------------+

PHPEl codigo para ejecutar el procedimiento seria como este:$conexion = new mysqli('localhost', 'curso', 'digitever', 'cursophp');$existencia = 10;$sql = "call productos_inventariobajo_cuantos($existencia,@out_cuantos)";$registros = $conexion->query($sql, MYSQLI_STORE_RESULT);$sql = 'SELECT @out_cuantos as cuantos';$registros = $conexion->query($sql, MYSQLI_STORE_RESULT);$numeroRegistros = $registros->num_rows;$registro = $registros->fetch_object();echo htmlspecialchars($registro->cuantos,ENT_QUOTES,'ISO-8859-1');echo '<br>';$registros->close();$conexion->close();

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 45

Page 46: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

VistasOtra de las novedades de MySQL 5 son las vistas o views. Una vista es un estatuto sql que se guarda en el servidor y se maneja como si fuera una tabla regular.

Ejemplo 1CREATE OR REPLACE VIEW vw_categorias_proveedores AS SELECT DISTINCT categorias.claveCategoria, categorias.categoria, proveedores.claveProveedor, proveedores.proveedor FROM categorias, productos, proveedores WHERE

categorias.claveCategoria = productos.claveCategoria AND proveedores.claveProveedor = productos.claveProveedor

ORDER BY categorias.categoria

Esta vista simula una tabla que define que proveedores surten cuales categorias de productos, en los clientes (modo texto, gui, web) las vistas aparecen como una tabla mas.

las consultas sobre la vista son iguales a una tabla comun:SELECT * FROM vw_categorias_proveedores+----------------+-----------------+----------------+----------------------------------------+| claveCategoria | categoria | claveProveedor | proveedor |+----------------+-----------------+----------------+----------------------------------------+| 1 | Bebidas | 7 | Pavlova, Ltd. || 1 | Bebidas | 18 | Aux joyeux ecclésiastiques || 1 | Bebidas | 10 | Refrescos Americanas LTDA || 1 | Bebidas | 12 | Plutzer Lebensmittelgroßmõrkte AG || 1 | Bebidas | 16 | Bigfoot Breweries || 1 | Bebidas | 20 | Leka Trading || 1 | Bebidas | 23 | Karkki Oy || 1 | Bebidas | 1 | Exotic Liquids || . | . | . | . || . | . | . | . || . | . | . | . || 7 | Vegetales | 6 | Mayumi's || 7 | Vegetales | 24 | G'day, Mate || 7 | Vegetales | 12 | Plutzer Lebensmittelgroßmõrkte AG || 7 | Vegetales | 4 | Tokyo Traders || 7 | Vegetales | 3 | Grandma Kelly's Homestead |+----------------+-----------------+----------------+----------------------------------------+

Se pueden filtrar los resultados que arroja la vista:SELECT * FROM vw_categorias_proveedores WHERE categoria = 'carnes';+----------------+-----------+----------------+-----------------------------------+| claveCategoria | categoria | claveProveedor | proveedor |+----------------+-----------+----------------+-----------------------------------+| 6 | Carnes | 12 | Plutzer Lebensmittelgroßmõrkte AG || 6 | Carnes | 24 | G'day, Mate || 6 | Carnes | 7 | Pavlova, Ltd. || 6 | Carnes | 25 | Ma Maison || 6 | Carnes | 4 | Tokyo Traders |+----------------+-----------+----------------+-----------------------------------+

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 46

Page 47: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

En PHP se ejecuta lis vista como cualquier otro estatuto:$conexion = @new mysqli('localhost', 'curso', 'digitever', 'cursophp');$sql = 'SELECT * FROM vw_categorias_proveedores';$registros = @$conexion->query($sql, MYSQLI_STORE_RESULT);while ($registro = $registros->fetch_object()){

echo htmlspecialchars($registro->claveCategoria,ENT_QUOTES,'ISO-8859-1') . ' - ';echo htmlspecialchars($registro->categoria,ENT_QUOTES,'ISO-8859-1') . ' - ';echo htmlspecialchars($registro->claveProveedor,ENT_QUOTES,'ISO-8859-1') . ' - ';echo htmlspecialchars($registro->proveedor,ENT_QUOTES,'ISO-8859-1') . '<br>';

}

Ejemplo 2CREATE OR REPLACE VIEW vw_productos_clientes AS SELECT DISTINCT productos.claveProducto, productos.producto, clientes.claveCliente, clientes.cliente, Sum(pedidosDetalle.cantidad) AS cantidadOrdenada FROM productos, clientes, pedidosDetalle, pedidos WHERE

productos.claveproducto = pedidosDetalle.claveproducto AND pedidosdetalle.clavepedido = pedidos.clavepedido AND pedidos.clavecliente = clientes.clavecliente

GROUP BY productos.claveProducto, productos.producto, clientes.claveCliente, clientes.cliente ORDER BY productos.producto;

Esta vista define una tabla que define que productos son ordenamos por cuales clientes y en que cantidad.

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Código Fuente Puerto 80 Puerto 8080 Puerto 8085Codigo Fuente Puerto 80 Puerto 8080 Puerto 8085

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 47

Page 48: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Separar usuario y password de codigo fuenteGeneralmente la informacion necesaria para establecer la conexion con la base de datos es incluida en el codigo fuente de la aplicacion, por ejemplo:

$conexion = @new mysqli('localhost', 'curso', 'digitever', 'cursophp');

En caso que se quiera separar la informacion del usuario y password para no estarlos poniendo fijos o hardcoded en las paginas donde se requiere la informacion hay dos opciones comunmente utilizadas:• Agregar variables de entorno accesibles a la aplicacion• Definir valores de fault de las directivas de php relacionadas con la base de datos

Por ejemplo, supongamos que tenemos dos aplicaciones web alojadas en diferentes directorios:

Considerando los siguientes requerimientos:• La aplicacion webapp1 requiere conectarse con la base de datos y webapp2 no. • La aplicacion webapp2 no requiere conexion con base de datos. • No queremos definir los valores del usuario y password en el codigo fuente de webapp1.• Los valores del del usuario y password debes estar disponibles unicamente para webapp1, webapp2 no

debe tener acceso a ellos.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 48

Page 49: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Variables de entornoEn este caso vamos a solicitarle al Apache que agregue dos variables de entorno que esten diponibles unicamente para los archivos del directorio de webapp1. Guardamos las variables de entorno en un archivo que este alojado en un directorio que no este accesible a traves de la aplicacion web, por ejemplo:

En este caso el archivo .dbuser contiene los siguientes valores:

Descripcion de los valores:• # : Es un comentario para documentar las directivas de Apache• SetEnv : Directiva que agrega una variable de entorno accesible para los modulos de Apache• DB_USER y DB_PASS : Nombres asignados a las variables de entorno• "cursophp" y "digitever" : Valores de las variables de entorno

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 49

Page 50: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

En httpd.conf tendriamos los alias de las diferentes aplicaciones web:

Para el alias de webapp1, agregamos la directiva Include: indicando que para el directorio a donde apunta el alias de la apliacion incluya el contenido del archivo .dbuser.

De esta manera las variables de entorno DB_USER y DB_PASS estan disponibles unicamente para las paginas alojadas en el directorio de webapp1.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 50

Page 51: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Si solicitamos una pagina con la funcion phpinfo() alojada en el directorio de webapp1 tenemos acceso a las variables de entorno:

Por otra parte si solicitamos la misma informacion de webapp2, no tenemos acceso a las variables de entorno:

En el codigo php de webapp1 obtenemos las variables mediante el superglobal $_SERVER:$conexion = @new mysqli('localhost',

$_SERVER['DB_USER'], $_SERVER['DB_PASS'], 'cursophp');

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 51

Page 52: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Directivas de phpEn lugar de variables de entorno podemos definir valores deafult para el usuario, password y host de MySQL. Se le solicita al Apache que de de alta estos valores para los archivos del directorio de webapp1. Guardamos las variables de entorno en un archivo que este alojado en un directorio que no este accesible a traves de la aplicacion web, por ejemplo:

El archivo .phpAdmin contiene directivas de PHP relacionadas con MySQL:

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 52

Page 53: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

En httpd.conf tendriamos los alias de las diferentes aplicaciones web:

Para el alias de webapp1, agregamos la directiva Include: indicando que para el directorio a donde apunta el alias de la apliacion incluya el contenido del archivo .phpAdmin.

De esta manera los valores default para la conexion con MySQL estan disponibles unicamente para las paginas alojadas en el directorio de webapp1.

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 53

Page 54: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Si solicitamos una pagina con la funcion phpinfo() alojada en el directorio de webapp1 tenemos acceso a los valores de las directivas:

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 54

Page 55: PHP - MySQLisacorp.awardspace.com/MySQLi.pdf · • Que el servidor de MySQL sea version 4.1.3 o superior ... rutinas , clases, tutoriales, utilerias, etc.) desarrolladas con la extension

PHP - MySQLi

Por otra parte si solicitamos la misma informacion de webapp2, no tenemos acceso a las variables de entorno:

En el codigo php de webapp1 podemos obtener los valores de las directivas en el momento de la conexion:// Obtener valores para extablecer conexioncon MySQL$mysqlHost = ini_get('mysqli.default_host');$mysqlUser = ini_get('mysqli.default_user');$mysqlPassword = ini_get('mysqli.default_pw');

// Conectarse$conexion = @new mysqli($mysqlHost, $mysqlUser, $mysqlPassword, 'cursophp');

Elaborado por Jorge Eduardo Torres Lozano ([email protected]) para uso exclusivo de Digitever 55