Instrucciones predefinidas
El concepto básico de instrucción predefinida es enviar a MySQL, por una parte una plantilla con la consulta que queremos ejecutar y por otras los datos. Esto puede resultarnos útil a la hora de ejecutar varias consultas iguales, como por ejemplo inserciones o borrados en bloque, además de ayudarnos a prevenir ataques de inyección SQL. Además son muy útiles para acelerar la ejecución cuando se ejecutan varias consultas iguales con diferentes datos. Por último destacar que tienen un funcionamiento similar a los PreparedStatement de JDBC del lenguaje JAVA.
Veamos un ejemplo de inserción con la metodología orientada a procedimientos:
<?php
$db = mysqli_connect('localhost', 'comprador', 'proweb2013', 'uazon');
// Definimos la plantilla de la consulta.
$consulta =
"INSERT INTO libros(isbn, titulo,n_pags,precio,fk_editoriales) " .
" VALUES(?, ?, ?, ?, ?)";
// Inicializamos la sentencia preparada.
$stmt = mysqli_stmt_init($db);
//preparamos la consulta
if (mysqli_stmt_prepare($stmt, $consulta) !== false) {
$isbn = 123456789;
$titulo = 'Zen to Done';
$n_pags = 150;
$precio = 10.99;
$fk_editoriales = 8; //foreig key -> EDITORIALES (Alfaguara)
// Asociamos parametros a la plantilla
mysqli_stmt_bind_param($stmt, "isiii", $isbn, $titulo,
$n_pags, $precio, $fk_editoriales);
mysqli_stmt_execute($stmt);
echo mysqli_stmt_affected_rows($stmt).' libro insertado.';
// Finalizamos el uso de la plantilla
mysqli_stmt_close($stmt);
}
mysqli_close($db);
?>
Ejemplo de inserción con la metodología orientada a objetos:
<?php
$db = new mysqli('localhost', 'comprador', 'proweb2013', 'uazon');
// Definimos la plantilla de la consulta.
$consulta =
"INSERT INTO libros(isbn,titulo,n_pags,precio,fk_editoriales) ".
" VALUES(?, ?, ?, ?, ?)";
// Instanciamos la plantilla.
$stmt = $db->stmt_init();
if ($stmt->prepare($consulta) !== false) {
$isbn = 123456789;
$titulo = 'Zen to Done';
$n_pags = 150;
$precio = 10.99;
$fk_editoriales = 8; //foreign key -> EDITORIALES (Alfaguara)
// Asociamos parametros a la plantilla
$stmt->bind_param("isiii",
$isbn,$titulo,$n_pags,$precio,$fk_editoriales);
$stmt->execute();
echo $stmt->affected_rows.' libro insertado.';
// Finalizamos el uso de la plantilla
$stmt->close();
}
$db->close();
?>
Veamos el ejemplo más detenidamente.
En primer lugar creamos la sentencia preparada con mysqli_stmt_init o $db->stmt_init().
**Procedimientos:**
mysqli_stmt mysqli_stmt_init ( mysqli $identificador_de_enlace)
Ejemplo:
// Inicializamos la sentencia preparada.
$stmt = mysqli_stmt_init ($db);
**Objetos:**
class mysqli {
mysqli_stmt stmt_init ( void )
}
En nuestro ejemplo:
// Inicializamos la sentencia preparada.
$stmt = $db->stmt_init();
Lo importante de esta función y método es que devuelven una instancia de la clase MySQLI_STMT que representa una sentencia preparada. Más información en el manual de PHP: http://www.php.net/manual/es/class.mysqli-stmt.php
En segundo lugar preparamos la consulta comprobando que es correcta. En el ejemplo tenemos la siguiente consulta:
// Definimos la plantilla de la consulta.
$consulta = "INSERT INTO libros (isbn, titulo,n_pags,precio,fk_editoriales) " .
" VALUES(?, ?, ?, ?, ?)";
La consulta que le pasamos puede incluir uno o más marcadores de parámetro, insertando el carácter interrogativo (?) en la posición apropiada.
Los marcadores sólo son válidos en la lista VALUES() de una sentencia INSERT, o en una comparación en una cláusula WHERE. Sin embargo, no son permitidos para identificadores (tales como nombres de tabla o columna), en el listado de los nombres de las columnas a ser devueltas por la sentencia SELECT, o para especificar operadores.
Veamos como preparar la instrucción predefinida:
**Procedimientos:**
bool mysqli_stmt_prepare ( mysqli_stmt $stmt, string $consulta)
Ejemplo:
// Preparamos la consulta
if (mysqli_stmt_prepare($stmt, $consulta) !== false)
{
**Objetos:**
class mysqli_stmt {
mixed prepare ( string $consulta )
}
En nuestro ejemplo:
// Preparamos la consulta
if ($stmt->prepare($consulta) !== false)
{
El tercer paso será asociar las variables a la plantilla, de tal manera que las variables deben coincidir con los marcadores de (?) que pusimos en la misma. Para eso utilizaremos:
**Procedimientos:**
bool mysqli_stmt_bind_param( mysqli_stmt $stmt, string $tipos,
mixed &$var1 [, mixed &$... ] )
Ejemplo:
// Asociamos parametros a la plantilla
mysqli_stmt_bind_param($stmt, "isiii", $isbn, $titulo,
$n_pags, $precio, $fk_editoriales);
**Objetos:**
class mysqli_stmt {
mixed bind_param ( string $tipos, mixed &$var1 [, mixed &$... ] )
}
En nuestro ejemplo:
// Asociamos parametros a la plantilla
$stmt->bind_param("isiii", $isbn, $titulo, $n_pags, $precio, $fk_editoriales);
Tanto la función como el método reciben una cadena de formato similar a la de printf donde se especificará el número y los tipos de las variables que van a ir a continuación.
En nuestro ejemplo pasamos la cadena "**isiis**", donde indicamos que hay cinco parámetros, el primero entero ("i" de integer), el segundo cadena ("s" de string), el tercero y cuarto enteros y el último cadena.
En la tabla que aparece a continuación podemos ver los diferentes tipos de parámetros que podemos usar dentro de una sentencia preparada.
Diferentes opciones para definir un parámetro en la plantilla de una sentencia preparada
Carácter | Descripción |
---|---|
i | La variable correspondiente tiene tipo entero |
d | La variable correspondiente tiene tipo doble |
s | La variable correspondiente tiene tipo string |
b | La variable correspondiente tiene tipo BLOB y será enviada en paquetes |
A continuación pasaremos las variables coincidiendo en número y tipo con el formato.
Una vez hecha la asociación(bind) podremos ejecutar la sentencia, para ello utilizaremos:
**Procedimientos:**
bool mysqli_stmt_execute ( mysqli_stmt $stmt )
Ejemplo:
// Ejecutamos instrucción
mysqli_stmt_execute ($stmt);
**Objetos:**
class mysqli_stmt {
mixed execute ( void )
}
En nuestro ejemplo:
// Ejecutamos instrucción
$stmt->execute();
Devuelven TRUE o FALSE en caso de éxito o error respectivamente.
Como es un INSERT podremos consultar el número de filas insertadas. Utilizaremos:
**Procedimientos:**
int mysqli_stmt_affected_rows ( mysqli_stmt $stmt )
Ejemplo:
printf("Libros insertados: %d\n", mysqli_stmt_affected_rows($stmt));
**Objetos:**
class mysqli_stmt {
int affected_rows
}
En nuestro ejemplo:
echo $stmt->affected_rows.' libro insertado.';
Este proceso de bind y execute puede estar en un bucle si vamos a realizar más de una inserción.
Por último debemos liberar el manejador de sentencias, cancelando cualquier resultado pendiente con las siguientes instrucciones:
**Procedimientos:**
bool mysqli_stmt_close ( mysqli_stmt $stmt )
Ejemplo:
mysqli_stmt_close($stmt);
**Objetos:**
class mysqli_stmt {
bool stmt_close ( void )
}
En nuestro ejemplo:
$stmt->close();
Como vemos en el ejemplo también podremos hacerlo usando objetos con un proceso idéntico.
Si lo que deseamos es obtener resultados con un SELECT tras el stmt_execute deberemos obtenerlos con mysqli_stmt_bind_result y después usar mysqli_stmt_fetch para obtener los valores. Para profundizar más en este tema se recomienda visitar este enlace: http://php.net/manual/es/function.mysqli-stmt-bind-result.php
<?php
$db = new mysqli('localhost', 'comprador', 'proweb2013', 'uazon');
$descripcion = " %". addslashes('guerra')." %";
$query = "SELECT titulo FROM libros where titulo like ?";
$stmt = $db->stmt_init();
if ($stmt->prepare($query) !== false) {
$stmt->bind_param("s", $descripcion);
$stmt->execute();
$stmt->store_result(); //averiguar el numero de filas
echo $stmt->num_rows . ' libros encontrados.<br>';
$stmt->bind_result($titulo);
while ($stmt->fetch()) {
echo stripslashes($titulo) . "<br>";
}
$stmt->free_result();
$stmt->close();
}
$db->close();
?>